package com.istock.union.user.service.impl;

import java.text.ParseException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;

import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.DateUtils;
import org.apache.ibatis.session.ExecutorType;
import org.apache.ibatis.session.SqlSession;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;

import com.istock.base.common.api.model.PageInfo;
import com.istock.base.mybatis.utils.MybatisFieldConvertUtils;
import com.istock.union.user.dao.CredentialRoleInfoMapper;
import com.istock.union.user.dao.RoleInfoMapper;
import com.istock.union.user.dao.RoleMenuInfoMapper;
import com.istock.union.user.dao.ext.ExtRoleInfoMapper;
import com.istock.union.user.model.Constants;
import com.istock.union.user.model.CredentialRoleInfoExample;
import com.istock.union.user.model.RoleInfo;
import com.istock.union.user.model.RoleInfoExample;
import com.istock.union.user.model.RoleInfoModel;
import com.istock.union.user.model.RoleInfoQueryModel;
import com.istock.union.user.model.RoleMenuInfo;
import com.istock.union.user.model.RoleMenuInfoExample;
import com.istock.union.user.service.RoleInfoService;

@Repository
public class RoleInfoServiceImpl implements RoleInfoService{

	@Autowired
	private RoleInfoMapper roleInfoMapper;
	
	@Autowired
	private ExtRoleInfoMapper extRoleInfoMapper;
	
	@Autowired
	private RoleMenuInfoMapper roleMenuInfoMapper;
	
	@Autowired
	private SqlSessionFactoryBean sessionFactory;
	
	@Autowired
	private CredentialRoleInfoMapper credentialRoleMapper;

	private Logger logger = LoggerFactory.getLogger(getClass());
	/**
	 * 分页查询角色信息
	 * 
	 * @param role
	 * @param page
	 * @return
	 */
	public List<RoleInfo> selectRoleListByPage(RoleInfoQueryModel role, PageInfo<RoleInfo> page) {
		return roleInfoMapper.selectByExample(createQuery(role), page);
	}

	/**
	 * 查询角色信息
	 * 
	 * @param role
	 * @param page
	 */
	public List<RoleInfo> selectRoleList(RoleInfoQueryModel role) {
		return roleInfoMapper.selectByExample(createQuery(role));
	}
	
	private RoleInfoExample createQuery(RoleInfoQueryModel role) {
		RoleInfoExample example = new RoleInfoExample();
		RoleInfoExample.Criteria criteria = example.createCriteria();
		if (null != role) {
			if (StringUtils.isNotBlank(role.getRoleKey())) {
				criteria.andRoleKeyLike("%" + role.getRoleKey() + "%");
			}
			if (StringUtils.isNotBlank(role.getRoleName())) {
				criteria.andRoleNameLike("%" + role.getRoleName() + "%");
			}
			if (null != role.getDataScope()) {
				criteria.andDataScopeEqualTo(role.getDataScope());
			}
			if (StringUtils.isNotBlank(role.getBeginTime())) {
				try {
					criteria.andCreateTimeGreaterThanOrEqualTo(DateUtils.parseDate(role.getBeginTime()));
				} catch (ParseException e) {
					logger.error("parse beginTime "+role.getBeginTime()+" exception " , e);
				}
			}
			if (StringUtils.isNotBlank(role.getEndTime())) {
				try {
					criteria.andCreateTimeLessThan(DateUtils.parseDate(role.getEndTime()));
				} catch (ParseException e) {
					logger.error("parse endTime "+role.getEndTime()+" exception " , e);
				}
			}
			if(StringUtils.isNotBlank(role.getOrderByColumn())) {
//				example.setOrderByClause(NamedConverter.HumpToUnderline(role.getOrderByColumn())+" "+role.getIsAsc());
				example.setOrderByClause(MybatisFieldConvertUtils.getInstance().unmarshal("com.istock.union.user.dao.RoleInfoMapper", "BaseResultMap", role.getOrderByColumn())+" "+role.getIsAsc());
			}
		}
		if(StringUtils.isBlank(example.getOrderByClause())) {
			example.setOrderByClause(" CREATE_TIME ASC");
		}
		
		return example;
	}

	/**
	 * 新增角色和关联信息
	 * 
	 * @param role
	 * @return
	 */
	@Transactional
	public void insertRole(RoleInfoModel role) {
		insertRoleInfo(role);
		insertRoleMenus(role.getId(), Arrays.asList(role.getMenuIds()));
	}

	private void insertRoleInfo(RoleInfoModel role) {
		role.setCreateTime(new Date());
		role.setStatus(Constants.COMMON_VALID);
		int num = roleInfoMapper.insertSelective(role);
		if (num != 1) {
			logger.error("Data role insert failed, expect 1, but {}, role {}", num, role);
			throw new RuntimeException("数据保存记录异常");
		}
	}
	
	private void insertRoleMenus(String roleId, List<String> menuIds) {
		int num = 0;
		try {
			num = batchInsertRoleMenus(roleId, menuIds);
		} catch (Exception e) {
			logger.error("Data role menu insert exception ", e);
			throw new RuntimeException("插入异常");
		}
		if (num != menuIds.size()) {
			logger.error("Data role menu insert failed, expect 1, but {}", num);
			throw new RuntimeException("插入异常");
		}
	}

	/**
	 * 批量插入
	 * 
	 * @param roleId
	 * @return
	 * @throws Exception 
	 */
	public int batchInsertRoleMenus(String roleId, List<String> menuIds) throws Exception {
		if (CollectionUtils.isEmpty(menuIds)) {
			return 0;
		}
		int rows = 0;
		// 新增用户与角色管理
		SqlSession session = sessionFactory.getObject().openSession(ExecutorType.BATCH);
		RoleMenuInfoMapper mapper = session.getMapper(RoleMenuInfoMapper.class);
		for (String menuId : menuIds) {
			RoleMenuInfo rm = new RoleMenuInfo();
			rm.setRoleId(roleId);
			rm.setMenuId(menuId);
			mapper.insertSelective(rm);
			rows++;
		}
		session.flushStatements();
		return rows;
	}

	/**
	 * 根据ID查询角色信息
	 * 
	 * @param id
	 * @return
	 */
	public RoleInfo selectRoleById(String id) {
		RoleInfoExample example = new RoleInfoExample();
		RoleInfoExample.Criteria criteria = example.createCriteria();
		criteria.andIdEqualTo(id);
//		criteria.andStatusEqualTo(Constants.COMMON_VALID);
		List<RoleInfo> list = roleInfoMapper.selectByExample(example);
		if (CollectionUtils.isEmpty(list)) {
			return null;
		}
		return list.get(0);
	}

	/**
	 * 
	 * @param dept
	 * @return
	 */
	@Transactional
	public void updateRole(RoleInfoModel role) {
		int num = updateRoleInfo(role);
		if (num != 1) {
			logger.error("Data role update failed, expect 1, but {}, id {}", num, role.getId());
			throw new RuntimeException("更新异常");
		}
		deleteRoleMenus(role.getId());
		insertRoleMenus(role.getId(), Arrays.asList(role.getMenuIds()));
	}

	private void deleteRoleMenus(String roleId) {
		RoleMenuInfoExample example = new RoleMenuInfoExample();
		example.createCriteria().andRoleIdEqualTo(roleId);
		// 如果严格控制，需要先查询一次数量
		roleMenuInfoMapper.deleteByExample(example);
	}

	/**
	 * 更新角色信息
	 * 
	 * @param role
	 * @return
	 */
	public int updateRoleInfo(RoleInfo role) {
		role.setUpdateTime(new Date());
		return roleInfoMapper.updateByPrimaryKeySelective(role);
	}

	/**
	 * 根据ID批量删除角色
	 * 
	 * @param ids
	 */
	@Transactional
	public void deleteRoleByIds(String ids) {
		// TODO 暂时不作并发回滚控制
		Assert.isTrue(ids.length() >= 1, "id must not empty");
		List<String> roleIds = Arrays.asList(ids.split(","));
		for (String id : roleIds) {
			RoleInfo role = roleInfoMapper.selectByPrimaryKey(id);
			if (countRoleUsersByRoleId(id) > 0) {
				throw new RuntimeException(String.format("%1$s已分配,不能删除", role.getRoleName()));
			}
		}
		RoleInfoExample example = new RoleInfoExample();
		RoleInfoExample.Criteria criteria = example.createCriteria();
		criteria.andIdIn(roleIds);
		roleInfoMapper.deleteByExample(example);
		
		RoleMenuInfoExample roleMenuExample = new RoleMenuInfoExample();
		RoleMenuInfoExample.Criteria roleMenuCriteria = roleMenuExample.createCriteria();
		roleMenuCriteria.andRoleIdIn(roleIds);
		roleMenuInfoMapper.deleteByExample(roleMenuExample);
	}

	/**
	 * 通过角色ID查询角色使用数量
	 * 
	 * @param roleId
	 * @return
	 */
	public long countRoleUsersByRoleId(String roleId) {
		CredentialRoleInfoExample example = new CredentialRoleInfoExample();
		CredentialRoleInfoExample.Criteria criteria = example.createCriteria();
		criteria.andRoleIdEqualTo(roleId);
		return credentialRoleMapper.countByExample(example);
	}

	/**
	 * 校验角色名称是否已存在
	 * 
	 * @param role
	 * @return
	 */
	public Boolean checkRoleNameUnique(RoleInfo role) {
		RoleInfoExample example = new RoleInfoExample();
		RoleInfoExample.Criteria criteria = example.createCriteria();
		criteria.andRoleNameEqualTo(role.getRoleName());
		if (StringUtils.isNotBlank(role.getId())) {
			criteria.andIdNotEqualTo(role.getId());
		}
		return roleInfoMapper.countByExample(example) == 0;
	}

	/**
	 * 校验角色KEY是否存在
	 * 
	 * @param role
	 * @return
	 */
	public Boolean checkRoleKeyUnique(RoleInfo role) {
		RoleInfoExample example = new RoleInfoExample();
		RoleInfoExample.Criteria criteria = example.createCriteria();
		criteria.andRoleKeyEqualTo(role.getRoleKey());
		if (StringUtils.isNotBlank(role.getId())) {
			criteria.andIdNotEqualTo(role.getId());
		}
		return roleInfoMapper.countByExample(example) == 0;
	}

	/**
	 * 根据用户ID查询角色信息
	 * 会返回用户所在租户下所有角色
	 * 
	 * @param userId
	 * @return
	 */
	public List<RoleInfoModel> selectRolesByUserId(String userId) {
		List<RoleInfo> userRoles = selectUserRolesByUserId(userId);
		RoleInfoQueryModel query = null;
		if (userRoles != null && userRoles.size()>0) {
			query = new RoleInfoQueryModel();
			// 角色与租户不做关联
//			query.setTenantId(userRoles.get(0).getTenantId());
//			query.setStatus(Constants.COMMON_VALID);
		}
		List<RoleInfo> roleInfos = selectRoleList(query);
		List<RoleInfoModel> roleInfoList = new ArrayList<RoleInfoModel>();
		if(roleInfos != null) {
			for(RoleInfo item : roleInfos) {
				RoleInfoModel model = new RoleInfoModel();
				BeanUtils.copyProperties(item, model);
				roleInfoList.add(model);
			}
		}
//		List<RoleInfoModel> roleInfolist = BeanUtils.propertiesCopy(roleInfos, new RoleInfoModel());
		for (RoleInfoModel model : roleInfoList) {
			for (RoleInfo role : userRoles) {
				if (model.getId().equals(role.getId())) {
					model.setFlag(true);
					break;
				}
			}
		}
		return roleInfoList;
	}

	public List<RoleInfo> selectCredentialRole(String credentialId){
		return extRoleInfoMapper.findCredentialRoleList(credentialId);
	}
	
	/**返回user_role表中对应userId的roleId
	 * @param userId
	 * @return
	 */
	public List<String> findRoleIdByUser(String userId){
		List<RoleInfo> roleList = selectUserRolesByUserId(userId);
		List<String> result = new ArrayList<String>();
		if(roleList != null && roleList.size()>0){
			for(RoleInfo roleInfo : roleList){
				result.add(roleInfo.getId());
			}
		}
		return result;
	}

	@Override
	public List<RoleInfo> selectUserRolesByUserId(String userId) {
		return extRoleInfoMapper.findRoleListByUserId(userId);
	}
}
